﻿
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Service.Core.Identity.Handler;
using Service.Core.Identity.Model;
using Service.Framework;
using Service.Framework.AppStartup;
using Service.Framework.Utils;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using IdentityModel;
using Service.Core.Identity.Login;
using Service.Core.Redis.Services;

namespace Service.Core.Identity;

/// <summary>
/// 
/// </summary>
public class ClientIdentityStartup : StartupModule<ClientIdentityStartup>
{
    public override int Order { get; set; } = 50;
    /// <summary>
    /// 
    /// </summary>
    /// <param name="webApplicationBuilder"></param>
    public override void ConfigureServices(WebApplicationBuilder webApplicationBuilder)
    {


        JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
        AppSettings<IdsServiceConfigure> appSettings = webApplicationBuilder.Services.BuildServiceProvider().GetRequiredService<AppSettings<IdsServiceConfigure>>();
        webApplicationBuilder.Services.AddSingleton<IAuthorizationService, CustomAuthorizationService>();
        webApplicationBuilder.Services.AddAuthentication(o =>
        {
            o.DefaultScheme = "Bearer";
            o.DefaultChallengeScheme = nameof(ApiResponseHandler);
            o.DefaultForbidScheme = nameof(ApiResponseHandler);
        }).AddJwtBearer(options =>
             {
                 options.RequireHttpsMetadata = false;
                 options.Audience = Tools.GetAppName(webApplicationBuilder.Environment.ApplicationName);
                 options.Authority = appSettings.Instance.IdsConfig.Authority;
                 options.Events = GetJwtBearerEvents();
             }).AddScheme<AuthenticationSchemeOptions, ApiResponseHandler>(nameof(ApiResponseHandler), o => { });


        #region 角色策略
        // 策略必须配置redis才能使用
        var permissionRequirement = new PermissionRequirement(
            JwtClaimTypes.Role, //基于角色的授权
           TimeSpan.FromDays(1) //接口的过期时间
       );
        #endregion
        #region 内部策略
        var innerRequirement = new InnerRequirement();
        #endregion
        webApplicationBuilder.Services.AddAuthorization(options =>
        {
            options.AddPolicy(AuthPolicy.Permission,
                policy =>
                {
                    policy.RequireAuthenticatedUser();
                    policy.Requirements.Add(permissionRequirement);
                });
            options.AddPolicy(AuthPolicy.Inner,
                policy =>
                {
                    policy.Requirements.Add(innerRequirement);
                });
        });
        webApplicationBuilder.Services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
        webApplicationBuilder.Services.AddSingleton(permissionRequirement);
        webApplicationBuilder.Services.AddSingleton<IAuthorizationHandler, InnerHandler>();
        webApplicationBuilder.Services.AddSingleton(innerRequirement);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="webApplication"></param>
    public override void Configure(WebApplication webApplication)
    {


    }


    private static JwtBearerEvents GetJwtBearerEvents()
    {
        return new JwtBearerEvents()
        {
            //令牌验证成功后触发
            OnTokenValidated = async context =>
            {
                var subject = ((Microsoft.IdentityModel.JsonWebTokens.JsonWebToken)context.SecurityToken).Subject;
                //如果没有subject，说明是客户端用户或者是匿名用户
                if (string.IsNullOrWhiteSpace(subject))
                {
                    context.Success();
                    return;
                }
                var idsConfigAppSettings = context.HttpContext.RequestServices.GetRequiredService<AppSettings<IdsServiceConfigure>>();
                var redisService = context.HttpContext.RequestServices.GetRequiredService<IRedisService>();
                if (!await redisService.Database.KeyExistsAsync($"User:{subject}"))
                {
                    context.Fail("Redis Token is missing");
                }
                if (!idsConfigAppSettings.Instance.EnableMultiDeviceLogin)
                {
                    //使用JTI 来保持互斥
                    var jtiId = ((Microsoft.IdentityModel.JsonWebTokens.JsonWebToken)context.SecurityToken).Id;
                    var lastJti = await redisService.Database.StringGetAsync($"User:{subject}:latestJti");
                    if (!jtiId.Equals(lastJti))
                    {
                        context.Fail("EnableMultiDeviceLogin  is false");
                    }
                }
            },
            //验证失败时触发。
            OnAuthenticationFailed = async context =>
            {

            },
        };
    }
}
